#include "stdafx.h"

#include "MonitorBuffer.h"
#include "WriteableMonitorBuffer.h"
#include "ReservedBufferWriter.h"
#include "IPALMemoryServices.h"
#include "IPALDebuggingServices.h"
#include "IPALThreadingServices.h"


#include "IPALClock.h"
extern IPALClock * g_pPalClock;
extern double g_startTime;;




void WriteableMonitorBuffer::LockWrites()
{

	int lockCount;
	for ( 
		lockCount = GetPALThreadingServices()->InterlockedIncrement((int *)&this->m_in);
		lockCount > 1;
	lockCount = GetPALThreadingServices()->InterlockedIncrement((int *)&this->m_in) 
		)
	{
		GetPALThreadingServices()->InterlockedDecrement((int *)&this->m_in);
		GetPALDebuggingServices()->YieldSlice();
	}
}

void WriteableMonitorBuffer::ReleaseWrites()
{
	GetPALThreadingServices()->InterlockedDecrement((int *)&this->m_in);
}


ReservedBufferWriter * NewReservedBufferWriter()
{

	ReservedBufferWriter *pWriter = (ReservedBufferWriter *)GetPALMemoryServices()->OSMemoryAllocate( sizeof(ReservedBufferWriter));
	if ( pWriter )
		pWriter->Initialize();
	return pWriter;
}


ReservedBufferWriter * WriteableMonitorBuffer::Reserve( XUINT32 cAdditionalSize, XUINT64 processClocks )
{

	BYTE header[32];
	ReservedBufferWriter *pWriter;
	unsigned int cTotalSize = cAdditionalSize + 32;

	this->LockWrites();

	while ( cTotalSize > this->TotalAvailableIn() )
	{
		this->ReleaseWrites();
		GetPALDebuggingServices()->YieldSlice();
		this->LockWrites();
	}
	pWriter = NewReservedBufferWriter();
	if ( pWriter )
	{
		pWriter->m_pFirstBlock = this->pIn();

		pWriter->m_firstBlockSize = MIN(cTotalSize, this->ContiguousAvailableIn());

		memset(this->pIn(), NULL, MIN(4u, pWriter->m_firstBlockSize));
		if ( cTotalSize == pWriter->m_firstBlockSize )
		{
			pWriter->m_pSecondBlock = 0;
			pWriter->m_secondBlockSize = 0;
			if ( pWriter->m_firstBlockSize + this->m_out >= 0x10000 )
				this->m_out = 0;
			else
				this->m_out += pWriter->m_firstBlockSize;
		}
		else
		{
			pWriter->m_pSecondBlock = &this->m_buffer[4];
			pWriter->m_secondBlockSize = cTotalSize - pWriter->m_firstBlockSize;
			if ( pWriter->m_firstBlockSize < 4 )
				memset(&this->m_buffer[4], 0, 4 - pWriter->m_firstBlockSize);
			this->m_out = pWriter->m_secondBlockSize;
		}
		*(DWORD *)header = 0;
		*(DWORD *)&header[4] = cAdditionalSize + 32;


		*(QWORD *)&header[8] = processClocks;

		*(double *)&header[16] = g_pPalClock->GetAbsoluteTimeInSeconds() - g_startTime;

		*(DWORD *)&header[24] = GetPALMemoryServices()->GetCurrentThreadId();
		pWriter->WriteBytes(0x20u, header);
	}

	this->ReleaseWrites();
	return pWriter;
}
